package com.hzdaba.aiapi.scheduler;

import com.hzdaba.aiapi.service.AiNumListService;
import com.hzdaba.aiapi.vo.AiApiResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

@Component
public class NumsImportResultCheckScheduler {

    /**
     * 访问 Redis
     */
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 缓存每批号码成功导入数的 key
     * 这个名字实在不好取
     */
    @Value("${aiapi.ainumlist.import.batches.success.count.cache.key}")
    private String keyOfImportSuccess;

    /**
     * 处理号码相关业务的对象
     */
    @Autowired
    private AiNumListService aiNumListService;

    /**
     * RestTemplate 对象
     */
    @Autowired
    private RestTemplate restTemplate;

    /**
     * 最少检查次数，检查次数达到这个值才判断是否导入成功
     */
    @Value("${aiapi.ainumlist.import.result.check.scheduler.min.count}")
    private int neededCount;

    /**
     * 记录每笔请求需要导入号码数的 key
     */
    @Value("${aiapi.ainumlist.import.batches.expected.count.cache.key}")
    private String keyOfExpectedCount;

    /**
     * 每笔导入请求的回调地址
     */
    @Value("${aiapi.ainumlist.import.batches.respurl.cache.key}")
    private String keyOfRespUrl;

    /**
     * 存放每笔导入号码请求被检查的次数
     */
    private Map<String, Integer> countMap = new HashMap<>();

    /**
     * 缓存导入失败的批次 id的 key
     */
    @Value("${aiapi.ainumlist.import.batches.failure.batchid.cache.name}")
    private String keyOfFailedBatchId;

    /**
     * 日志记录器
     */
    private static final Logger logger = LoggerFactory.getLogger(NumsImportResultCheckScheduler.class);

    /**
     * 定时检查每笔导入号码请求是否执行成功
     */
    @Scheduled(cron = "${aiapi.ainumlist.import.result.check.scheduler.cron}")
    public void toCheck() {
        //从 Redis 中取出所有导入请求
        Map<Object, Object> keysAndValues = this.redisTemplate.opsForHash().entries(this.keyOfExpectedCount);

        for (Map.Entry<Object, Object> entry : keysAndValues.entrySet()) {//便利每一笔导入请求

            String key = (String) entry.getKey();
            int neededSize = (Integer) entry.getValue();

            Integer checkedCount = this.countMap.get(key);//这比请求检查过几次

            if (checkedCount == null) {//首次检查
                this.countMap.put(key, 1);
                continue;
            } else if (checkedCount < this.neededCount) {//还没有达到最少检查次数
                this.countMap.put(key, checkedCount + 1);
                continue;
            } else {//达到了最少检查次数，正是检查
                this.doCheck(key, neededSize);
            }
        }
    }

    /**
     * 检查号码是否导入成功
     *
     * @param key        批次id:请求id
     * @param neededSize 需要导入的数量
     */
    private void doCheck(String key, Integer neededSize) {
        String[] segmentsOfKey = key.split(":");

        String batchId = segmentsOfKey[0];//批次id
        String reqId = segmentsOfKey[1];//请求id
        Integer importedSize = (Integer) this.redisTemplate.opsForHash().get(this.keyOfImportSuccess, key);//成功导入的数量
        String respUrl = (String) this.redisTemplate.opsForHash().get(this.keyOfRespUrl, key);//回调地址

//        StringBuilder logBuilder = new StringBuilder("检查号码导入是否成功。")
//                .append("批次 id ：").append(batchId).append("；")
//                .append("请求 id ：").append(reqId).append("；")
//                .append("回调地址：").append(respUrl).append("；")
//                .append("需要导入的号码数量：").append(neededSize).append("；")
//                .append("实际导入的号码数量：").append(importedSize).append("；");

        AiApiResponse aiApiResponse = null;

        if (importedSize == null || importedSize < neededSize) {//导入数量没有达到要求
            //删除这个批次的数据
            this.aiNumListService.deleteAiNumListByBatchId(batchId);
//在 Redis 中记录这个批次，尽可能避免再次新增这一批次的数据
            this.redisTemplate.opsForHash().put(this.keyOfFailedBatchId, batchId, reqId);

            if (ThreadLocalRandom.current().nextInt(100) == 0) {//随机数是0，设置过期时间
                //这个过期时间直接写死吧，配置文件太乱了
                this.redisTemplate.expire(this.keyOfFailedBatchId, 30, TimeUnit.MINUTES);
            }

            aiApiResponse = AiApiResponse.fail(batchId);
//            logBuilder.append("导入结果：失败；");
        } else {//导入数量达到了要求，删除这笔请求的缓存
            this.redisTemplate.opsForHash().delete(this.keyOfImportSuccess, key);
            this.redisTemplate.opsForHash().delete(this.keyOfExpectedCount, key);
            this.redisTemplate.opsForHash().delete(this.keyOfRespUrl, key);
            aiApiResponse = AiApiResponse.success(batchId);
//            logBuilder.append("导入结果：成功；");
        }

        if (respUrl != null && respUrl.length() > 0) {//回调地址不为空
            String responseOfCallback = null;

            try {
                responseOfCallback = this.restTemplate.postForObject(respUrl, aiApiResponse, String.class);
//                logBuilder.append("回调结果：成功；");
            } catch (RestClientException e) {
//                logBuilder.append("回调结果：失败；");
            }

//            logBuilder.append("回调响应：").append(responseOfCallback);
        }

        if (ThreadLocalRandom.current().nextInt(100) == 0) {
            this.countMap = new HashMap<>();
        }

//        logger.info(logBuilder.toString());
    }

}
